/**
 * @file logger.cpp
 * @author Yunfeng.Bo (Yunfeng.Bo@gmail.com)
 * @brief
 * @version 0.1
 * @date 2021-02-22
 *
 * @copyright Copyright (c) 2021
 *
 */
#include "logger.h"

// windows console color
#define NONE "\033[m"
#define RED "\033[0;32;31m"
#define LIGHT_RED "\033[1;31m"
#define GREEN "\033[0;32;32m"
#define LIGHT_GREEN "\033[1;32m"
#define BLUE "\033[0;32;34m"
#define LIGHT_BLUE "\033[1;34m"
#define DARY_GRAY "\033[1;30m"
#define CYAN "\033[0;36m"
#define LIGHT_CYAN "\033[1;36m"
#define PURPLE "\033[0;35m"
#define LIGHT_PURPLE "\033[1;35m"
#define BROWN "\033[0;33m"
#define YELLOW "\033[1;33m"
#define LIGHT_GRAY "\033[0;37m"
#define WHITE "\033[1;37m"

namespace common {
namespace log {
void coloring_formatter(boost::log::record_view const& rec, boost::log::formatting_ostream& strm) {
    auto date_time_formatter =
        boost::log::expressions::stream
        << boost::log::expressions::format_date_time<boost::posix_time::ptime>(
               "TimeStamp", "\033[0;36m[%Y-%m-%d %H:%M:%S.%f]\033[0m");
    date_time_formatter(rec, strm);

    boost::log::value_ref<boost::log::trivial::severity_level> level =
        boost::log::extract<boost::log::trivial::severity_level>("Severity", rec);

    switch (level.get()) {
    case boost::log::trivial::severity_level::trace:
        strm << GREEN;
        break;
    case boost::log::trivial::severity_level::debug:
        strm << LIGHT_GREEN;
        break;
    case boost::log::trivial::severity_level::info:
        strm << CYAN;
        break;
    case boost::log::trivial::severity_level::warning:
        strm << BROWN;
        break;
    case boost::log::trivial::severity_level::error:
        strm << PURPLE;
        break;
    case boost::log::trivial::severity_level::fatal:
        strm << RED;
        break;
    default:
        break;
    }

    strm << " [" << level << "]:  " << rec[boost::log::expressions::smessage]
         << "\033[0m";   // Restore the default color
}

void make_logger(std::string dir, std::string filename) {
    static bool once = true;
    if (once) {
        std::string log_dir = dir;

        std::filesystem::path log_path(log_dir);

        // 不存在就创建
        if (!std::filesystem::exists(log_path))
            std::filesystem::create_directories(log_path);

        // 确保结尾正确
        char dir_last_char = log_dir.at(log_dir.size() - 1);
        if (dir_last_char != '/' || dir_last_char != '\\')
            log_dir += "/";

        // 日志文件前缀
        std::string log_file_prefix = log_dir + filename + "_";

        // 日志内容格式
        // static const std::string COMMON_FMT_CONSOLE("[%TimeStamp%]
        // [%Severity%]: %Message%");
        static const std::string COMMON_FMT_FILE("[%TimeStamp%] [%Severity%]:  %Message%");

        boost::log::register_simple_formatter_factory<boost::log::trivial::severity_level, char>(
            "Severity");

        // Output message to console
        auto console_sink =
            boost::log::add_console_log(std::cout,
                                        // boost::log::keywords::format = COMMON_FMT_CONSOLE,
                                        boost::log::keywords::auto_flush = true);

        console_sink->set_formatter(&coloring_formatter);

        // Output message to file, rotates when file reached 1mb or at midnight
        // every day. Each log file is capped at 1mb and total is 20mb
        auto file_sink = boost::log::add_file_log(
            boost::log::keywords::file_name     = log_file_prefix + "%Y-%m-%d_%5N.log",
            boost::log::keywords::rotation_size = 1 * 1024 * 1024,
            boost::log::keywords::max_size      = 20 * 1024 * 1024,
            boost::log::keywords::time_based_rotation =
                boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
            boost::log::keywords::format     = COMMON_FMT_FILE,
            boost::log::keywords::auto_flush = true);

        boost::log::add_common_attributes();

        // Only output message with INFO or higher severity in Release
#ifdef DEBUG
        console_sink->set_filter(boost::log::trivial::severity >= boost::log::trivial::trace);

        file_sink->set_filter(boost::log::trivial::severity >= boost::log::trivial::debug);
#else
        file_sink->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
#endif
    }
    once = false;
}
}   // namespace log
}   // namespace common